package com.road.vast.springboot.config;

import com.road.vast.springboot.realm.CustomRealm;
import com.road.vast.springboot.session.CustomSessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.apache.shiro.mgt.SecurityManager;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author 郭泽鹏
 * @Date 2020/8/3 17:13
 * @Version 1.0
 * @Description shiro配置类
 */

@Configuration
public class ShiroConfiguration {
    //redis的ip地址和端口
    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;


    //1.创建realm
    @Bean
    public CustomRealm getRealm(){
        return new CustomRealm();
    }

    //2.创建安全管理器
    @Bean
    public SecurityManager getSecurityManager(CustomRealm realm){
        //会话管理器默认使用ServletContainerSessionManager，数据保存再HttpSession中
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);

        //将自定义的会话管理器注册到会话管理器中
        securityManager.setSessionManager(sessionManager());
        //将自定义的redis缓存管理器注册到会话管理器中
        securityManager.setCacheManager(cacheManager());

        return securityManager;
    }

    //3.配置shiro的过滤器工厂
    /**
     * 在web程序中，shiro进行权限控制全部是通过一组过滤器集合进行控制
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        //1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();

        //2.设置安全管理器
        filterFactory.setSecurityManager(securityManager);

        //3.通用配置（跳转到登录页面，未授权跳到的页面）
        filterFactory.setLoginUrl("/project/user/autherror/1");
        filterFactory.setUnauthorizedUrl("/project/user/autherror/2");

        //4.设置过滤器集合
        /**
         * 设置所有的过滤器，有顺序map
         *      key = 拦截的url地址
         *      value = 过滤器类型
         */
        Map<String, String> filterMap = new LinkedHashMap<>();

        //配置具有某种权限才能访问
        //第一种方式：使用过滤器的形式配置请求地址的 依赖权限
//        filterMap.put("/project/user/home", "perms[user-home]");        //不具备指定的权限，跳转到setUnauthorizedUrl指定得地址

        //配置具有某种角色才能访问
        //第一种方式：使用过滤器的形式配置请求地址的 依赖角色
//        filterMap.put("/project/user/home", "roles[系统管理员]");

        //当前请求地址可以匿名访问：可以直接访问
//        filterMap.put("/project/user/login", "anon");

        //当前请求地址必须认证之后才可以访问
        filterMap.put("/project/user/**", "authc");

        filterFactory.setFilterChainDefinitionMap(filterMap);
        return filterFactory;
    }

    //4.开启对shiro注解的支持
    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
    /**
 　　* 开启shiro aop注解支持.
 　　* 使用代理方式;所以需要开启代码支持;
 　　*/
   @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
       AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
     return authorizationAttributeSourceAdvisor;
    }

    //shiro整合redis：使用自定义的会话管理器
    /**
     * 1.redis的控制器，才做redis
     */
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host + ":" + port);
        return redisManager;
    }


    /**
     * 2.sessionDao
     */
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 3.会话管理器
     */
    public DefaultWebSessionManager sessionManager(){
        CustomSessionManager sessionManager = new CustomSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * 4.缓存管理器
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager cacheManager = new RedisCacheManager();
        cacheManager.setRedisManager(redisManager());
        return cacheManager;
    }
}
